home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 351-375 / disk_352 / treewalk / filter.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  20KB  |  716 lines

  1. /*
  2.  * Filter - the code to deal with filter expressions. We have one parser,
  3.  * and one executer. The parser is passed a pointer to a bunch of tokens,
  4.  * terminated by a null. We return the pointer to the next token, or NULL
  5.  * to indicate a parse error.
  6.  *
  7.  *    Copyright (C) 1989  Mike Meyer
  8.  *
  9.  *    This program is free software; you can redistribute it and/or modify
  10.  *    it under the terms of the GNU General Public License as published by
  11.  *    the Free Software Foundation; either version 1, or any later version.
  12.  *
  13.  *    This program is distributed in the hope that it will be useful,
  14.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  *    GNU General Public License for more details.
  17.  *
  18.  *    You should have received a copy of the GNU General Public License
  19.  *    along with this program; if not, write to the Free Software
  20.  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  */
  22.  
  23. #include <exec/types.h>
  24. #include <libraries/dos.h>    /* To get FileInfoBlock definition */
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <ctype.h>
  29. #include "errors.h"
  30.  
  31. /*
  32.  * We turn an expression into a linked list of nodes, which will be executed
  33.  * as a reverse polish expression.
  34.  */
  35. static struct node {
  36.     char        n_type ;        /* What it is */    
  37.     char        n_subtype ;        /* And more of same */
  38.     struct node    *n_next ;        /* Next node to interpret */
  39.     union {
  40.         long            un_int ;
  41.         char            *un_string ;
  42.         long            (*un_func)(struct FileInfoBlock *) ;
  43.         struct node        *un_short ;
  44.         } n_data ;
  45.     } ;
  46. #define n_prec        n_data.un_int    /* For operators... */
  47. #define n_int        n_data.un_int
  48. #define n_string    n_data.un_string
  49. #define n_func        n_data.un_func
  50. #define n_short        n_data.un_short    /* short-circuit pointer */
  51. #define n_date        n_data.un_date
  52.  
  53. /* Major types */
  54. #define NODE_BOGUS    0    /* Node of unknown type */
  55. #define NODE_DATA    1    /* data of type subtype */
  56. #define NODE_FUNC    2    /* Zeroadic function, returning subtype */
  57. #define NODE_REXX    3    /* Unidentified operand, feed it to Rexx */
  58. #define NODE_SHORTCIRC    4    /* target node for short-circuit ops */
  59. #define NODE_OP        5    /* Operator, precedence in n_prec */
  60. #define NODE_UOP    6    /* Unary op, precedence ditto */
  61.  
  62. /* Data types subtype */
  63. #define    NODE_INT    1
  64. #define NODE_STRING    2
  65. #define NODE_ANY    3
  66.  
  67. /* built-in oerators subtypes, unary */
  68. #define NODE_BITNOT    0
  69. #define NODE_NOT    1
  70. #define NODE_LP        2
  71. #define NODE_RP        3
  72.  
  73. /* And binary */
  74. #define NODE_LT        0
  75. #define NODE_LE        1
  76. #define NODE_GT        2
  77. #define NODE_GE        3
  78. #define NODE_EQ        4
  79. #define    NODE_NE        5
  80. #define NODE_BITAND    6
  81. #define NODE_BITOR    7
  82. #define NODE_BITXOR    8
  83. #define NODE_AND    9
  84. #define NODE_OR        10
  85. #define NODE_UPAT    11
  86. #define NODE_APAT    12
  87. #define NODE_NOTUPAT    13
  88. #define NODE_NOTAPAT    14
  89.  
  90. /* Functions supplied by main for twiddling FileInfoBlocks */
  91. extern long fibkey(struct FileInfoBlock *) ;
  92. extern long fibdirtype(struct FileInfoBlock *) ;
  93. extern char *fibname(struct FileInfoBlock *) ;
  94. extern long fibprot(struct FileInfoBlock *) ;
  95. extern long fibtype(struct FileInfoBlock *) ;
  96. extern long fibsize(struct FileInfoBlock *) ;
  97. extern long fibblock(struct FileInfoBlock *) ;
  98. extern long fibdate(struct FileInfoBlock *) ;
  99. extern long fibday(struct FileInfoBlock *) ;
  100. extern char *fibcomment(struct FileInfoBlock *) ;
  101. extern long askuser(struct FileInfoBlock *) ;
  102. extern long isdir(struct FileInfoBlock *) ;
  103. extern long isfile(struct FileInfoBlock *) ;
  104. extern char *fullname(struct FileInfoBlock *) ;
  105. extern long dofib(char *, long (*)(struct FileInfoBlock *)) ;
  106. extern long dorexx(char *, struct FileInfoBlock *) ;
  107.  
  108. /*
  109.  * token arrays hold all the tokens we know about.
  110.  */
  111. struct token {
  112.     char    *o_name ;
  113.     char    o_type ;
  114.     char    o_subtype ;
  115.     long    o_value ;
  116.     } ;
  117.  
  118. /* ops holds the things that can't be applied to files */
  119. static struct token ops[] = {
  120.     /* Functions first, so we can set them later. Nuts */
  121.     {"user",    NODE_FUNC,    NODE_INT,    /* (long) &askuser */ 0},
  122.     {"dir",        NODE_FUNC,    NODE_INT,    /* (long) &isdir */ 0},
  123.     {"file",    NODE_FUNC,    NODE_INT,    /* (long) &isfile */ 0},
  124.     {"filename",    NODE_FUNC,    NODE_STRING,    /* (long) &fullname */ 0},
  125.  
  126.     /* a couple of constants */
  127.     {"false",    NODE_DATA,    NODE_INT,    0},
  128.     {"true",    NODE_DATA,    NODE_INT,    1},
  129.  
  130.     {"!",        NODE_UOP,     NODE_NOT,    70},
  131.     {"<",        NODE_OP,    NODE_LT,    30},
  132.     {"<=",        NODE_OP,    NODE_LE,    30},
  133.     {">",        NODE_OP,    NODE_GT,    30},
  134.     {">=",        NODE_OP,    NODE_GE,    30},
  135.     {"==",        NODE_OP,    NODE_EQ,    30},
  136.     {"!=",        NODE_OP,    NODE_NE,    30},
  137.     {"=*",        NODE_OP,    NODE_UPAT,    30},
  138.     {"=#",        NODE_OP,    NODE_APAT,    30},
  139.     {"!*",        NODE_OP,    NODE_NOTUPAT,    30},
  140.     {"!#",        NODE_OP,    NODE_NOTAPAT,    30},
  141.     {"&",        NODE_OP,    NODE_BITAND,    60},
  142.     {"|",        NODE_OP,    NODE_BITOR,    40},
  143.     {"^",        NODE_OP,    NODE_BITXOR,    50},
  144.     {"~",        NODE_UOP,    NODE_BITNOT,    70},
  145.     {"&&",        NODE_OP,    NODE_AND,    20},
  146.     {"||",        NODE_OP,    NODE_OR,    10},
  147.     {"(",        NODE_UOP,    NODE_LP,    0},
  148.     {")",        NODE_UOP,    NODE_RP,    0},    /* Prec is ignored */
  149.  
  150.     {NULL,        0,        0,        0},
  151.     } ;
  152. /* Alias for the precedence of ops in this mess */
  153. #define o_prec    o_value
  154.  
  155. /* fibfuncs holds the mapping from tokens to operand primitives. */
  156. static struct token fibfuncs[] = {
  157.     /* Fib extraction functions */
  158.     {"diskkey",        NODE_FUNC,    NODE_INT,    /* (long) &fibkey */ 0},
  159.     {"direntrytype",    NODE_FUNC,    NODE_INT,    /* (long) &fibdirtype */ 0},
  160.     {"name",        NODE_FUNC,    NODE_STRING,    /* (long) &fibname */ 0},
  161.     {"protection",        NODE_FUNC,    NODE_INT,    /* (long) &fibprot */ 0},
  162.     {"entrytype",        NODE_FUNC,    NODE_INT,    /* (long) &fibtype */ 0},
  163.     {"size",        NODE_FUNC,    NODE_INT,    /* (long) &fibsize */ 0},
  164.     {"numblock",        NODE_FUNC,    NODE_INT,    /* (long) &fibblock */ 0},
  165.     {"date",        NODE_FUNC,    NODE_INT,    /* (long) &fibdate */ 0},
  166.     {"day",            NODE_FUNC,    NODE_INT,    /* (long) &fibday */ 0},
  167.     {"comment",        NODE_FUNC,    NODE_STRING,    /* (long) &fibcomment */ 0},
  168.     {NULL,            0,        0,        0},
  169.     } ;
  170.  
  171. /* Nasty bug in Lattice makes this routine necessary. Shitheads. */
  172. static void
  173. unlatticecode(void) {
  174.     fibfuncs[0].o_value = (long) &fibkey ;
  175.     fibfuncs[1].o_value = (long) &fibdirtype ;
  176.     fibfuncs[2].o_value = (long) &fibname ;
  177.     fibfuncs[3].o_value = (long) &fibprot ;
  178.     fibfuncs[4].o_value = (long) &fibtype ;
  179.     fibfuncs[5].o_value = (long) &fibsize ;
  180.     fibfuncs[6].o_value = (long) &fibblock ;
  181.     fibfuncs[7].o_value = (long) &fibdate ;
  182.     fibfuncs[8].o_value = (long) &fibday ;
  183.     fibfuncs[9].o_value = (long) &fibcomment ;
  184.     ops[0].o_value = (long) &askuser ;
  185.     ops[1].o_value = (long) &isdir ;
  186.     ops[2].o_value = (long) &isfile ;
  187.     ops[3].o_value = (long) &fullname ;
  188.     }
  189.  
  190. /*
  191.  * findop finds an operator/operand and returns the pointer to it, or
  192.  * NULL if it's not recognized.
  193.  */
  194. static struct token *
  195. findop(char *name, struct token *table) {
  196.  
  197.     while (table->o_name)
  198.         if (!(stricmp(table->o_name, name))) return table ;
  199.         else table += 1 ;
  200.     return NULL ;
  201.     }
  202.  
  203. /* functions used to deal with "`"'ed strings */
  204. long date(char *) ;
  205. long prot(char *) ;
  206.  
  207. /*
  208.  * lex gets the next token out of the strings it's given, build a node
  209.  * to put into it's second argument, and returns the new pointer. For
  210.  * various reasons, it expects things to start on a non-blank.
  211.  */
  212. #define EQPRE    "=!<>*#"    /* can be an op if concatenated with '=' */
  213. #define DUPOPS    "&|"        /* Ops if duplicated */
  214. #define OPCHARS    "&|^()<>"    /* Single-character ops */
  215. static char *
  216. lex(char *line, struct node *out) {
  217.     char            save, *end, *fibf, buf[160] ;
  218.     struct token        *top ;
  219.  
  220.     line = stpblk(line) ;
  221.     if (!*line) return NULL ;    /* No more data! */
  222.  
  223.     /* Is it a number? */
  224.     if (isdigit(*line)) {
  225.         if (tolower(line[1]) != 'x') save = *line == '0' ? 8 : 10 ;
  226.         else {
  227.             line += 2 ;
  228.             save = 16 ;
  229.             }
  230.         out->n_int = strtol(line, &end, save) ;
  231.         out->n_type = NODE_DATA ;
  232.         out->n_subtype = NODE_INT ;
  233.         return end ;
  234.         }
  235.  
  236.     /* How about a string? */
  237.     if (*line == '\'' || *line == '"' || *line == '`') {
  238.         save = *line ;
  239.         line += 1 ;
  240.         end = strchr(line, save) ;
  241.         if (end == NULL) {
  242.             fprintf(stderr, "%s: Unterminated string: %s\n", my_name, line) ;
  243.             errorflag = ERROR_HALT ;
  244.             return NULL ;
  245.             }
  246.         *end = '\0' ;
  247.         out->n_type = NODE_DATA ;
  248.         if (save != '`') {
  249.             out->n_subtype = NODE_STRING ;
  250.             strlwr(line) ;
  251.             out->n_string = line ;
  252.             }
  253.         else {
  254.             if ((out->n_int = date(line)) == -1
  255.             &&  (out->n_int = prot(line)) == -1) {
  256.                 fprintf(stderr, "%s: Invalid constant %s\n",
  257.                     my_name, line) ;
  258.                 errorflag = ERROR_HALT ;
  259.                 return NULL ;
  260.                 }
  261.             out->n_subtype = NODE_INT ;
  262.             }
  263.         return end + 1 ;
  264.         }
  265.                 
  266.     /* OK, try builtin operators & operands */
  267.     end = line ;
  268.     if (strchr(EQPRE, *line)) {    /* needs special handling */
  269.         if (*++end == '=') end += 1 ;
  270.         else if (*end == '#') end += 1 ;
  271.         else if (*end == '*') end += 1 ;
  272.         }
  273.     else if (strchr(DUPOPS, *line)) {
  274.         if (*line == *++end) end += 1 ;
  275.         }
  276.     else if (!strchr(OPCHARS, *line))
  277.         end = stptok(line, buf, 160, OPCHARS EQPRE " \t") ;
  278.  
  279.     save = *end ;
  280.     *end = '\0' ;
  281.  
  282.     /* See if it's a know operator or operand */
  283.     if (!(top = findop(line, ops)))
  284.         top = findop(line, fibfuncs)  ;
  285.  
  286.     if (top) {
  287.         out->n_type = top->o_type ;
  288.         out->n_subtype = top->o_subtype ;
  289.         out->n_int = top->o_value ;
  290.         }
  291.  
  292.     /* Or maybe a fibfunc applied to a named file */
  293.     else {
  294.         if ((fibf = strrchr(line, '.'))
  295.         && (top = findop(fibf + 1, fibfuncs))) {
  296.             out->n_type = NODE_DATA ;
  297.             out->n_subtype = top->o_subtype ;
  298.             *fibf = '\0' ;
  299.             out->n_int = dofib(line,
  300.                 (long (*)(struct FileInfoBlock *)) top->o_value) ;
  301.             *fibf = '.' ;
  302.             }
  303. #ifndef    NO_REXX
  304.         else {    /* Don't know what it is, so make it arexx */
  305.             out->n_type = NODE_REXX ;
  306.             out->n_subtype = NODE_INT ;
  307.             if (!(out->n_string = strdup(line))) {
  308.                 errorflag = ERROR_HALT ;
  309.                 fprintf(stderr, "%s: out of memory!\n", my_name) ;
  310.                 }
  311.             }
  312. #else
  313.         else out->n_type = NODE_BOGUS ;
  314. #endif
  315.         }
  316.  
  317.     *end = save;
  318.     return end ;
  319.     }
  320.  
  321. /* push is used during parsing to maintain the operator stack */
  322. static void push(struct node **stack, long value, char type, char subtype) ;
  323.  
  324. /*
  325.  * parse parses the tokens in argv, and puts the resulting RPN code in code
  326.  */
  327. struct node *
  328. parse(char *line) {
  329.     struct node    *last = NULL, *code = NULL, now, *tmp, *stack = NULL ;
  330.     char        *token ;
  331.     int        operand = 1, shorted = 0 ;
  332.  
  333.     unlatticecode() ;
  334.  
  335.     while (!errorflag) {
  336.         token = line ;
  337.         if ((line = lex(line, &now)) == NULL || now.n_type == NODE_BOGUS)
  338.             break ;
  339.  
  340.         /* Check for operands or left paren */
  341.         else if (operand) {
  342.             if (now.n_type == NODE_OP) {
  343.                 now.n_type = NODE_BOGUS ;
  344.                 break ;
  345.                 }
  346.             else if (now.n_type == NODE_UOP) {
  347.                 if (now.n_subtype == NODE_RP) {
  348.                     now.n_type = NODE_BOGUS ;
  349.                     break ;
  350.                     }
  351.                 push(&stack, now.n_prec, now.n_type, now.n_subtype) ;
  352.                 continue ;
  353.                 }
  354.             else if ((tmp = (struct node *) malloc(sizeof(struct node))) == NULL) {
  355.                 fprintf(stderr, "%s: out of memory!", my_name) ;
  356.                 errorflag = ERROR_HALT ;
  357.                 }
  358.             else {
  359.                 tmp->n_type = now.n_type ;
  360.                 tmp->n_subtype = now.n_subtype ;
  361.                 tmp->n_int = now.n_int ;
  362.                 if (last != NULL) last->n_next = tmp ;
  363.                 else code = tmp ;
  364.                 last = tmp ;
  365.                 }
  366.             operand = 0 ;
  367.             }
  368.  
  369.         /* If not an operand, then we want an operator */
  370.         else if (now.n_type == NODE_OP) {
  371.             while (stack && stack->n_prec >= now.n_prec) {
  372.                 last->n_next = stack ;
  373.                 last = stack ;
  374.                 stack = stack->n_next ;
  375.                 }
  376.             if (now.n_subtype != NODE_AND && now.n_subtype != NODE_OR)
  377.                 push(&stack, now.n_prec, now.n_type, now.n_subtype) ;
  378.             else { /* Short circuit ops are screwy */
  379.                 if ((tmp = (struct node *) malloc(sizeof(struct node))) == NULL) {
  380.                     fprintf(stderr, "%s: out of memory!", my_name) ;
  381.                     errorflag = ERROR_HALT ;
  382.                     }
  383.                 else {
  384.                     push(&stack, now.n_prec, NODE_SHORTCIRC, now.n_subtype) ;
  385.                     tmp->n_type = now.n_type ;
  386.                     tmp->n_subtype = now.n_subtype ;
  387.                     tmp->n_short = stack ;
  388.                     last->n_next = tmp ;
  389.                     last = tmp ;
  390.                     shorted = 1 ;
  391.                     }
  392.                 }
  393.             operand = 1 ;
  394.             }
  395.  
  396.         /* But a right paren will do instead */
  397.         else if (now.n_type == NODE_UOP && now.n_subtype == NODE_RP) {
  398.             while (stack && !(stack->n_type == NODE_UOP && stack->n_subtype == NODE_LP)) {
  399.                 last->n_next = stack ;
  400.                 last = stack ;
  401.                 stack = stack->n_next ;
  402.                 }
  403.             if (!stack) {
  404.                 fprintf(stderr, "%s: To many right parens in filter\n",
  405.                     my_name) ;
  406.                 errorflag = ERROR_HALT ;
  407.                 }
  408.             /* Now, pop the stack sans checking */
  409.             last->n_next = stack ;
  410.             stack = stack->n_next ;
  411.             free(last->n_next) ;
  412.             }
  413.  
  414.         /* And anything else is an out-of-place token */
  415.         else {
  416.             now.n_type = NODE_BOGUS ;
  417.             break ;
  418.             }
  419.         }
  420.  
  421.     if (now.n_type == NODE_BOGUS) {
  422.         *line = '\0' ;
  423.         fprintf(stderr, "%s: Looking for %s, found %s\n", my_name,
  424.             operand ? "operand" : "operator", stpblk(token)) ;
  425.         errorflag = ERROR_HALT ;
  426.         return NULL ;
  427.         }
  428.  
  429.     if (operand) {
  430.         fprintf(stderr, "%s: filter ended unexpectedly\n", my_name) ;
  431.         errorflag = ERROR_HALT ;
  432.         return NULL ;
  433.         }
  434.  
  435.     /* Move the rest of the stacked ops to code */
  436.     while (stack) {
  437.         if (stack->n_type == NODE_UOP && stack->n_subtype == NODE_LP) {
  438.             fprintf(stderr, "%s: To many left parens in filter\n",
  439.                 my_name) ;
  440.             errorflag = ERROR_HALT ;
  441.             return NULL ;
  442.             }
  443.         last->n_next = stack ;
  444.         last = stack ;
  445.         stack = stack->n_next ;
  446.         }
  447.  
  448.     last->n_next = NULL ;
  449.  
  450. #ifdef    NO_REXX
  451.     /*
  452.      * Remove any shorts in the code. This is a marginal win, saving
  453.      * an execute loop for every && or || node that doesn't short-circuit.
  454.      * About every fourth or fifth node can be so shorted, so if they
  455.      * short 1/2 the time, you need to look at about 10 files before this
  456.      * wins. If you examine and fail to short-circuit at least the number
  457.      * of nodes, you definitely with. However, if you're using the REXX
  458.      * interface, then you almost cerainly lose, so we take this out.
  459.      */
  460.     while (shorted) {
  461.         shorted = 0 ;
  462.         for (last = code; last; last = last->n_next) {
  463.             if (last->n_next && last->n_next->n_type == NODE_SHORTCIRC) {
  464.                 last->n_next = last->n_next->n_next ;
  465.                 shorted = 1 ;
  466.                 }
  467.             /*
  468.              * It's tempting to remove the n_short short circuit
  469.              * pointer here. However, they get skipped by the
  470.              * pc=pc->n_next in the execute loop. Removing them
  471.              * will break said loop.
  472.              */
  473.             }
  474.         }
  475. #endif
  476.  
  477. #ifdef    NOWAY
  478. for(last=code; last; last=last->n_next)
  479. printf("%d %d, ", last->n_type, last->n_subtype) ;
  480. putchar('\n') ;
  481. fflush(stdout) ;
  482. #endif
  483.  
  484.     return code ;
  485.     }
  486.  
  487. #ifndef    NO_REXX
  488. /*
  489.  * lex builds a string of nodes to execute; free_code throws that same
  490.  * string away. If you don't have a REXX interface, you only compile one
  491.  * string per execution, so it doesn't matter. With a REXX interface,
  492.  * you can compile an unknown number. Said memory leak can be deadly (how
  493.  * do you think I found it?), so we plug it.
  494.  */
  495. void
  496. free_code(struct node *top) {
  497.     struct node    *tmp ;
  498.  
  499.     while (top != NULL) {
  500.         tmp = top->n_next ;
  501.         free(top) ;
  502.         top = tmp ;
  503.         }
  504.     }
  505. #endif
  506.  
  507. /*
  508.  * Since we're doing RPN, we need a stack. push & pop maintain that stack.
  509.  */
  510. static void
  511. push(struct node **stack, long value, char type, char subtype) {
  512.     struct node    *tmp ;
  513.  
  514.     if ((tmp = (struct node *) malloc(sizeof(struct node))) == NULL) {
  515.         errorflag = ERROR_HALT ;
  516.         fprintf(stderr, "%s: out of memory!\n", my_name) ;
  517.         }
  518.     else {
  519.         tmp->n_type = type ;
  520.         tmp->n_subtype = subtype ;
  521.         tmp->n_int = value ;
  522.         tmp->n_next = *stack ;
  523.         *stack = tmp ;
  524.         }
  525.     }
  526.  
  527. static long
  528. pop(struct node **stack, short subtype) {
  529.     long        out ;
  530.     struct node    *tmp ;
  531.  
  532.     if (!*stack) {
  533.         errorflag = ERROR_HALT ;
  534.         fprintf(stderr, "%s: expression evaluation error\n", my_name) ;
  535.         return 0 ;
  536.         }
  537.     if ((*stack)->n_type != NODE_DATA || ((*stack)->n_subtype & subtype) == 0) {
  538.         errorflag = ERROR_HALT ;
  539.         fprintf(stderr, "%s: operator applied to wrong type\n", my_name) ;
  540.         return 0 ;
  541.         }
  542.     tmp = *stack ;
  543.     *stack = (*stack)->n_next ;
  544.     out = tmp->n_int ;
  545.     free(tmp) ;
  546.     return out ;
  547.     }
  548. /*
  549.  * patcompare - handles the pattern-matching comparisons (=#, =*, !# & !*).
  550.  */
  551. long
  552. patcompare(struct node **stack, int ados) {
  553.     char    *sp, *pp ;
  554.     long    out ;
  555.  
  556.     pp = (char *) pop(stack, NODE_STRING) ;
  557.     sp = (char *) pop(stack, NODE_STRING) ;
  558.     if (ados) out = (astcsma(sp, pp) == strlen(sp)) ;
  559.     else  out = (stcsma(sp, pp) == strlen(sp)) ;
  560.     return out ;
  561.     }
  562.  
  563. /* To make pc visible from inside of cpr (mumble) */
  564. #define    pc    cp
  565.  
  566. /*
  567.  * execute is the outside entry. It gets top evaluated, and maps the
  568.  * result back to "true" or "false".
  569.  */
  570. long
  571. execute(struct FileInfoBlock *fib, struct node *code) {
  572.     struct node    *pc ;
  573.     long        tmp ;
  574.     struct node    *stack = NULL ;
  575.  
  576.     if (!code) return 1 ;
  577.     pc = code ;
  578.  
  579.     for (;pc && errorflag != ERROR_HALT; pc = pc->n_next) {
  580.         switch (pc->n_type) {
  581.             default:
  582.                 fprintf(stderr, "%s: Invalid code type %d\n", my_name,
  583.                 pc->n_type) ;
  584.             errorflag = ERROR_HALT ;
  585.             return 0 ;
  586.  
  587.             case NODE_SHORTCIRC: break ;    /* a nop */
  588.  
  589.             case NODE_DATA:
  590.             push(&stack, pc->n_int, NODE_DATA, pc->n_subtype) ;
  591.             break ;
  592.  
  593.             case NODE_FUNC:
  594.             push(&stack, (pc->n_func)(fib), NODE_DATA,
  595.                         pc->n_subtype) ;
  596.             break ;
  597.  
  598. #ifndef    NO_REXX
  599.             case NODE_REXX:
  600.             push(&stack, dorexx(pc->n_string, fib), NODE_DATA,
  601.                             pc->n_subtype) ;
  602.             break ;
  603. #endif
  604.  
  605.             case NODE_UOP:
  606.             switch (pc->n_subtype) {
  607.                 case NODE_BITNOT:
  608.                 push(&stack, ~pop(&stack, NODE_INT),
  609.                     NODE_DATA, NODE_INT) ;
  610.                 break ;
  611.                 case NODE_NOT:
  612.                 push(&stack, (long) !pop(&stack, NODE_INT),
  613.                     NODE_DATA, NODE_INT) ;
  614.                 break ;
  615.                 default:
  616.                 fprintf(stderr, "%s: Invalid unary op %x\n",
  617.                     my_name, pc->n_subtype) ;
  618.                 errorflag = ERROR_HALT ;
  619.                 return 0 ;
  620.                 }
  621.             break ;
  622.  
  623.             case NODE_OP:
  624.             switch (pc->n_subtype) {
  625.                 case NODE_LT:
  626.                 tmp = pop(&stack, NODE_INT) ;
  627.                 push(&stack,
  628.                     (long) (pop(&stack, NODE_INT) < tmp),
  629.                     NODE_DATA, NODE_INT) ;
  630.                 break ;
  631.                 case NODE_LE:
  632.                 tmp = pop(&stack, NODE_INT) ;
  633.                 push(&stack,
  634.                     (long) (pop(&stack, NODE_INT) <= tmp),
  635.                     NODE_DATA, NODE_INT) ;
  636.                 break ;
  637.                 case NODE_GT:
  638.                 tmp = pop(&stack, NODE_INT) ;
  639.                 push(&stack,
  640.                     (long) (pop(&stack, NODE_INT) > tmp),
  641.                     NODE_DATA, NODE_INT) ;
  642.                 break ;
  643.                 case NODE_GE:
  644.                 tmp = pop(&stack, NODE_INT) ;
  645.                 push(&stack,
  646.                     (long) (pop(&stack, NODE_INT) >= tmp),
  647.                     NODE_DATA, NODE_INT) ;
  648.                 break ;
  649.                 case NODE_EQ:
  650.                 push(&stack,
  651.                     (long) (pop(&stack, NODE_INT) == pop(&stack, NODE_INT)),
  652.                     NODE_DATA, NODE_INT) ;
  653.                 break ;
  654.                 case NODE_NE:
  655.                 push(&stack,
  656.                     (long) (pop(&stack, NODE_INT) != pop(&stack, NODE_INT)),
  657.                     NODE_DATA, NODE_INT) ;
  658.                 break ;
  659.                 case NODE_BITAND:
  660.                 push(&stack,
  661.                     pop(&stack, NODE_INT) & pop(&stack, NODE_INT),
  662.                     NODE_DATA, NODE_INT) ;
  663.                 break ;
  664.                 case NODE_BITOR:
  665.                 push(&stack,
  666.                     pop(&stack, NODE_INT) | pop(&stack, NODE_INT),
  667.                     NODE_DATA, NODE_INT) ;
  668.                 break ;
  669.                 case NODE_BITXOR:
  670.                 push(&stack,
  671.                     pop(&stack, NODE_INT) ^ pop(&stack, NODE_INT),
  672.                     NODE_DATA, NODE_INT) ;
  673.                 break ;
  674.                 case NODE_AND:
  675.                 tmp = pop(&stack, NODE_INT) ;
  676.                 if (!tmp) {
  677.                     push(&stack, tmp, NODE_DATA, NODE_INT) ;
  678.                     pc = pc->n_short ;
  679.                     }
  680.                 break ;
  681.                 case NODE_OR:
  682.                 tmp = pop(&stack, NODE_INT) ;
  683.                 if (tmp) {
  684.                     push(&stack, tmp, NODE_DATA, NODE_INT) ;
  685.                     pc = pc->n_short ;
  686.                     }
  687.                 break ;
  688.                 case NODE_APAT:
  689.                 push(&stack, patcompare(&stack, 1),
  690.                     NODE_DATA, NODE_INT) ;
  691.                 break ;
  692.                 case NODE_UPAT:
  693.                 push(&stack, patcompare(&stack, 0),
  694.                     NODE_DATA, NODE_INT) ;
  695.                 break ;
  696.                 case NODE_NOTAPAT:
  697.                 push(&stack, (long) !patcompare(&stack, 1),
  698.                     NODE_DATA, NODE_INT) ;
  699.                 break ;
  700.                 case NODE_NOTUPAT:
  701.                 push(&stack, (long) !patcompare(&stack, 0),
  702.                     NODE_DATA, NODE_INT) ;
  703.                 break ;
  704.                 default:
  705.                 fprintf(stderr, "%s: Invalid op %x\n", my_name,
  706.                     pc->n_subtype) ;
  707.                 errorflag = ERROR_HALT ;
  708.                 return 0 ;
  709.                 }
  710.             break ;
  711.             }
  712.         }
  713.     if (errorflag != ERROR_HALT) return pop(&stack, NODE_ANY) ;
  714.     else return 0 ;
  715.     }
  716.